// controllare i render...
WWL.calendar5 = function ( name, attrs )
{
	attrs = to_dict ( attrs || {} );
	var cal = new WWL ( "calendar5", name );

	cal.templates = dict ( {
		'container-start' : '<div class="cal-container %(class)s" id="%(name)s-container" style="%(style)s">',
		'container-end' : '</div>',

		'head-toolbar' : '%(prev)s %(month-year)s %(next)s<div class="cal-clear"></div>',
		'btn-prev' : '<div class="cal-wrap cal-wrap-prev"><div class="cal-button cal-button-prev" onclick="WWL.calendar5.action(\'%(name)s\',\'prev\')">&laquo;</div></div>',
		'btn-next' : '<div class="cal-wrap cal-wrap-next"><div class="cal-button cal-button-next" onclick="WWL.calendar5.action(\'%(name)s\',\'next\')">&raquo;</div></div>',
		'btn-month-year' : 
			'<div class="cal-wrap cal-wrap-month"><div class="cal-button" onclick="WWL.calendar5.action(\'%(name)s\',\'mode\',\'months\')">%(month_name)s</div></div>' +
			'<div class="cal-wrap cal-wrap-year"><div class="cal-button" onclick="WWL.calendar5.action(\'%(name)s\',\'mode\',\'years\')">%(year)s</div></div>',

		'box-days-start' : '<div class="cal-box cal-box-days">',
		'box-days-end' : '</div>',

		'dow' : '<div class="cal-dow">%(label)s</div>',
		'day-empty' : '<div class="cal-day cal-day-empty"></div>',
		'day' : '<div class="cal-day %(class)s"><div class="cal-button" onclick="WWL.calendar5.click(\'%(name)s\',\'%(day)s\')">%(label)s</div></div>',
		'day-clear' : '<div class="cal-clear"></div>',

		'box-select-start' : '<div class="cal-box %(class)s">',
		'box-select-end' : '</div>',

		'select' : '<div class="cal-wrap"><div class="cal-button" onclick="WWL.calendar5.action(\'%(name)s\',\'%(action)s\',\'%(value)s\')">%(label)s</div></div>',

		'today' : '<div class="cal-button cal-goto-today" onclick="WWL.calendar5.action(\'%(name)s\',\'today\')">Oggi</div>',

		'time' : '<div class="cal-time">%(content)s</div>',

		'number' : '<div class="cal-number">' +
			//'<div class="cal-button cal-number-dec" onclick="WWL.calendar5.action(\'%(name)s\',\'dec_%(type)s\')">-</div>' +
			'%(label)s<input type="number" value="%(value)02d" maxlength="2" min="0" max="%(max)d" onchange="WWL.calendar5.action(\'%(name)s\',\'set_%(type)s\',this.value)" />' +
			//'<div class="cal-button cal-number-inc" onclick="WWL.calendar5.action(\'%(name)s\',\'inc_%(type)s\')">+</div>' +
			'</div>',

		'popup' : '<div class="cal-popup-button"><input class="cal-text" type="text" id="%(name)s-text" value="%(value)s" pattern="%(pattern)s"  onchange="WWL.calendar5.action(\'%(name)s\',\'set_value\',this.value )" /><div class="cal-icon" onclick="WWL.calendar5.action(\'%(name)s\',\'popup\')"></div></div>',
		'day-id': 'cell%(name)s-%(year)s-%(month)s-%(day)s'
	} );

	cal._instances = [];
	cal.em = new liwe.event_manager ( cal );
	cal.valid_events ( [ 'click', 'render', 'render-day', 'render-month', 'render-year', 'change-day', 'change-month', 'change-year', 'change', 'set-mode' ] );
	cal.mode = 'days';

	cal.language = attrs.get ( 'language', 'it' );
	cal.use_time = attrs.get ( 'time', true );
	cal.is_popup = attrs.get ( 'popup', false );
	cal.date = Date.fromString ( attrs.get ( 'value' ) ) || new Date ();
	cal.date.setSeconds ( 0 );
	cal._visible = false;
	cal._rendered = false;
	cal._container = null;

	//custom templates
	var tmpl = attrs.get ( 'templates' );
	if ( tmpl && typeof ( tmpl ) == 'object' )
		cal.templates.inherits ( tmpl, true );
	
	cal.format = '%Y/%m/%d';
	cal.pattern = '\\d{1,2}/\\d{1,2}/\\d{4}';
	if ( cal.use_time )
	{
		cal.format += ' %H:%M:%s';
		cal.pattern += ' \\d{2}:\\d{2}:\\d{2}';
	}

	cal._setup = function ()
	{
		this.dow = this.date.getDay ();
		this.day = this.date.getDate ();
		this.month = this.date.getMonth () + 1;
		this.year = this.date.getFullYear ();

		this.hour = this.date.getHours ();
		this.minute = this.date.getMinutes ();
		//this.second = this.date.getSeconds ();
		this.second = 0;

		this.month_name = this.date.year_months [ this.language ] [ this.month - 1 ];
		this.dow_name = this.date.week_days [ this.language ] [ this.dow ];

		this.value = String.format ( '%02d/%02d/%04d', this.day, this.month, this.year );
		if ( this.use_time )
			this.value += String.format ( ' %02d:%02d:%02d', this.hour, this.minute, this.second );

		if ( $( this.name + '-text' ) )
			$( this.name + '-text' ).value = this.value;
	};

	cal.refresh = function ()
	{
		this._setup ();
		$( this._container, this._render_calendar () );
		this.dispatchEvent ( 'render', null, { 'cal' : this } );   
	};

	cal.popup = function ()
	{
		if ( ! this.is_popup ) return;
		if ( ! this._rendered ) this.render ();

		if ( cal._visible )
			cal.hide ();
		else
			cal.show ();
	};

	cal.hide = function ()
	{
		if ( ! this.is_popup ) return;

		liwe.dom.hide ( this._container );
		this._visible = false;
	};

	cal.show = function ()
	{
		if ( ! this.is_popup ) return;

		liwe.dom.show ( this._container );
		this._visible = true;
	};

	cal.click = function ( day )
	{
		this.dispatchEvent ( 'click', null, { 'day' : day, 'cal' : cal } );
		this.set_day ( day );
	};

	cal.prev = function ()
	{
		switch ( this.mode )
		{
			case 'days':
				this.set_month ( this.month - 1 );
				break;
			case 'years':
				this.set_year ( this.year - 24, true );
				break;
		}
	};

	cal.next = function ()
	{
		switch ( this.mode )
		{
			case 'days':
				this.set_month ( this.month + 1 );
				break;
			case 'years':
				this.set_year ( this.year + 24, true );
				break;
		}
	};

	cal.get_value = function ()
	{
		return Date.formatted ( this.format, this.date );
	};

	// {{{ setters
	cal.set_value = function ( val )
	{
		val = val || '';
		var parts = val.match ( /([0-9]{1,4}).([0-9]{1,2}).([0-9]{1,4})/ );
		if ( parts )
		{
			if ( parts [ 1 ].length == 4 )
				val = String.format ( "%04d/%02d/%02d", parts [ 1 ], parts [ 2 ], parts [ 3 ] );
			else
				val = String.format ( "%04d/%02d/%02d", parts [ 3 ], parts [ 2 ], parts [ 1 ] );
		}

		if ( val == '' )
			val = Date.formatted ( "%Y/%m/%d" );
			
		this.date = Date.fromString ( val );
		this.date.setSeconds ( 0 );
		this.refresh ();
	};

	cal.set_hour = function ( hour )
	{
		hour = this._check ( hour );
		this.date.setHours ( hour );
		this.refresh ();
	};

	cal.set_minute = function ( minute )
	{
		minute = this._check ( minute );
		this.date.setMinutes ( minute );
		this.refresh ();
	};

	cal.set_second = function ( second )
	{
		second = this._check ( second );
		this.date.setSeconds ( second );
		this.refresh ();
	};

	cal.set_day = function ( day )
	{
		day = this._check ( day );
		this.dispatchEvent ( 'change-day', null, { 'day' : day, 'cal' : cal } );
		this.dispatchEvent ( 'change', null, { 'day' : day, 'cal' : cal } ); 
		this.date.setDate ( day );
		this.refresh ();
	};

	cal.set_month = function ( month, skip_mode )
	{
		month = this._check ( month );
		this.dispatchEvent ( 'change-month', null, { 'month' : month, 'cal' : cal } ); 
		this.dispatchEvent ( 'change', null, { 'month' : month, 'cal' : cal } ); 
		if ( ! skip_mode )
			this.mode = 'days';
		this.date.setMonth ( month - 1 );
		this.refresh ();
	};

	cal.set_year = function ( year, skip_mode )
	{
		year = this._check ( year );
		this.dispatchEvent ( 'change-year', null, { 'year' : year, 'cal' : cal } );  
		this.dispatchEvent ( 'change', null, { 'year' : year, 'cal' : cal } );  
		if ( ! skip_mode )
			this.mode = 'days';
		this.date.setFullYear ( year );
		this.refresh ();
	};

	// }}}

	cal.set_mode = function ( mode )
	{
		this.dispatchEvent ( 'set-mode', null, { 'mode' : mode, 'cal' : cal } );   
		this.mode = mode;
		this.refresh ();
	};

	// {{{ calendar rendering
	cal.render = function ( dest_id )
	{
		if ( ! this._rendered )
		{
			dest_id = $el ( dest_id );

			if ( this.is_popup )
			{
				$( dest_id, this._render_popup () );
				this._container = $( this.name + '-container' );
			}
			else
				this._container = dest_id;

			this._rendered = true;
		}

		$( this._container, this._render_calendar () );
		this.dispatchEvent ( 'render', null, { 'cal' : this } );   
	};

	cal.to_string = function ()
	{
		if ( this.is_popup )
			return this._render_popup ();
		else
			return this._render_calendar ();
	};

	cal._render_popup = function ()
	{
		var buf = new String.buffer ();

		buf.add ( String.formatDict ( this.templates [ 'popup' ], this ) );
		buf.add ( String.formatDict ( this.templates [ 'container-start' ], { 'class' : this.is_popup ? 'cal-popup' : '', 'name' : this.name, 'style' : 'display:none' } ) );
		buf.add ( this.templates [ 'container-end' ] );

		return buf.toString ();
	};

	cal._render_calendar = function ()
	{
		var buf = new String.buffer ();

		if ( ! this.is_popup ) buf.add ( String.formatDict ( this.templates [ 'container-start' ], { 'class' : this.is_popup ? 'cal-popup' : '', 'name' : this.name, 'style' : '' } ) );

		// TOOLBAR
		buf.add ( String.formatDict ( cal.templates [ 'head-toolbar' ], {
			'prev' : String.formatDict ( cal.templates [ 'btn-prev' ], this ),
			'next' : String.formatDict ( cal.templates [ 'btn-next' ], this ),
			'month-year' : String.formatDict ( cal.templates [ 'btn-month-year' ], this )
		} ) );

		// MODE-BASED RENDER
		switch ( this.mode )
		{
			case 'days':
				this._render_days ( buf );
				break;
			case 'months':
				this._render_months ( buf );
				break;
			case 'years':
				this._render_years ( buf );
				break;
		};

		if ( ! this.is_popup ) buf.add ( this.templates [ 'container-end' ] );

		//this.dispatchEvent ( 'render', null, { 'cal' : cal } );   

		return buf.toString ();
	};

	cal._render_days = function ( buf )
	{
		var d = new Date ( cal.date.getFullYear (), cal.date.getMonth (), 1 );

		buf.add ( this.templates [ 'box-days-start' ] );

		// WEEK DAYS
		var dow_list = [ 1, 2, 3, 4, 5, 6, 0 ];
		for ( var i = 0; i < dow_list.length; i ++ )
		{
			var label = this.date.week_days [ this.language ] [ dow_list [ i ] ];
			label = label [ 0 ].toUpperCase () + label [ 1 ];

			var dct = { 'label' : label, 'cal' : cal };
			this.dispatchEvent ( 'render-dow', null, dct );

			buf.add ( String.formatDict ( this.templates [ 'dow' ], dct ) );
		}

		// DAY FILLER
		var dow_skip = [ 6, 0, 1, 2, 3, 4, 5 ];
		var dow = d.getDay ();
		var fill = dow_skip [ dow ];
		while ( fill -- )
			buf.add ( this.templates [ 'day-empty' ] );

		// MONTH DAYS
		var today = new Date ();
		today.setHours ( 0, 0, 0, 0 );
		today = today.getTime ();

		var curday = new Date ( this.date );
		curday.setHours ( 0, 0, 0, 0 );
		curday = curday.getTime ();

		var m = d.getMonth ();
		while ( m == d.getMonth () )
		{
			var time = d.getTime ();
			var cls = 'cal-dow-' + d.getDay ();

			if ( time == today )
				cls += ' cal-today';
			if ( time == curday )
				cls += ' cal-current';

			var dct = {
				'name' : this.name,
				'day' : d.getDate (),
				'month' : cal.month,
				'year' : cal.year,
				'label' : d.getDate (),
				'class': cls,
				'cal': cal
			};
			
			dct [ 'id' ] = String.formatDict ( cal.templates [ 'day-id' ] , dct ); 
			//this.dispatchEvent ( 'render-day',null, dct );
			buf.add ( String.formatDict ( this.templates [ 'day' ], dct ) );

			d.setDate ( d.getDate () + 1 );
		}
		buf.add ( this.templates [ 'day-clear' ] );
		buf.add ( this.templates [ 'box-days-end' ] );

		buf.add ( String.formatDict ( this.templates [ 'today' ], this ) );

		if ( this.use_time )
			this._render_time ( buf );
	};

	cal._render_time = function ( buf )
	{
		var content = new String.buffer ();
		var dct = {
			'name' : this.name
		};

		dct [ 'type' ] = 'hour';
		dct [ 'value' ] = this.hour;
		dct [ 'max' ] = 23;
		dct [ 'label' ] = 'Ora:';
		content.add ( String.formatDict ( this.templates [ 'number' ], dct ) );

		dct [ 'type' ] = 'minute';
		dct [ 'value' ] = this.minute;
		dct [ 'max' ] = 59;
		dct [ 'label' ] = ':';
		content.add ( String.formatDict ( this.templates [ 'number' ], dct ) );

		/*
		dct [ 'type' ] = 'second';
		dct [ 'value' ] = this.second;
		dct [ 'max' ] = 59;
		dct [ 'label' ] = ':';
		dct [ 'i' ] = 3;
		content.add ( String.formatDict ( this.templates [ 'number' ], dct ) );
		*/

		buf.add ( String.formatDict ( this.templates [ 'time' ], { 'content' : content } ) );
	};

	cal._render_months = function ( buf )
	{
		var dct = {
			'name' : this.name,
			'action' : 'set_month',
			'cal' : cal
		};

		buf.add ( String.formatDict ( this.templates [ 'box-select-start' ], { 'class' : 'cal-box-months' } ) );

		for ( var i = 0; i < 12; i ++ )
		{
			dct [ 'value' ] = ( i + 1 );
			dct [ 'label' ] = this.date.year_months [ this.language ] [ i ].substr ( 0, 3 );
			this.dispatchEvent ( 'render-month', null, dct );
			buf.add ( String.formatDict ( this.templates [ 'select' ], dct ) );
		}

		buf.add ( this.templates [ 'box-select-end' ] );
	};

	cal._render_years = function ( buf )
	{
		var dct = {
			'name' : this.name,
			'action' : 'set_year',
			'cal' : cal
		};

		buf.add ( String.formatDict ( this.templates [ 'box-select-start' ], { 'class' : 'cal-box-years' } ) );

		for ( var i = this.year - 12; i <= this.year + 12; i ++ )
		{
			dct [ 'value' ] = i;
			dct [ 'label' ] = i;
			this.dispatchEvent ( 'render-year', null, dct );
			buf.add ( String.formatDict ( this.templates [ 'select' ], dct ) );
		}

		buf.add ( this.templates [ 'box-select-end' ] );
	};
	// }}}

	cal._check = function ( val )
	{
		val = parseInt ( val, 10 );
		if ( isNaN ( val ) ) val = 0;
		return val;
	};

	cal._setup ();

	if ( cal.is_popup )
	{
		cal.addEventListener ( 'click', function ( e )
		{
			cal.hide ();
		} );
	};

	return cal;
};

WWL.calendar5.click = function ( id, day )
{
	var cal = WWL.get_instance ( 'calendar5', id );
	cal.click ( day );
};

WWL.calendar5.action = function ( id, action, value )
{
	var cal = WWL.get_instance ( 'calendar5', id );
	switch ( action )
	{
		case 'prev':
			cal.prev ();
			break;
		case 'next':
			cal.next ();
			break;
		case 'today':
			cal.set_value ( new Date () );
			break;
		case 'set_value':
			cal.set_value ( value );
			break;
		case 'inc_hour':
			cal.set_hour ( cal.date.getHours () + 1 );
			break;
		case 'dec_hour':
			cal.set_hour ( cal.date.getHours () - 1 );
			break;
		case 'set_hour':
			cal.set_hour ( value );
			break;
		
		case 'inc_minute':
			cal.set_minute ( cal.date.getMinutes () + 1 );
			break;
		case 'dec_minute':
			cal.set_minute ( cal.date.getMinutes () - 1 );
			break;
		case 'set_minute':
			cal.set_minute ( value );
			break;
		
		case 'inc_second':
			cal.set_second ( cal.date.getSeconds () + 1 );
			break;
		case 'dec_second':
			cal.set_second ( cal.date.getSeconds () - 1 );
			break;
		case 'set_second':
			cal.set_second ( value );
			break;
		
		case 'set_month':
			cal.set_month ( value );
			break;
		
		case 'set_year':
			cal.set_year ( value );
			break;
		
		case 'mode':
			cal.set_mode ( value );
			break;

		case 'popup':
			cal.popup ();
			break;
	};
};

